import { Hono } from 'hono'
import { cors } from 'hono/cors'
import { logger } from 'hono/logger'
import { ServiceContainer } from '../framework/container.js'
import { EventBus } from './events.js'
import { TaskScheduler } from './scheduler.js'
import { ConfigManager } from './config.js'
import { createLogger } from './logger.js'
import { WebSocketManager } from './websocket.js'
import { Database } from 'bun:sqlite'
import _ from 'lodash'

export class Application {
  constructor() {
    this.container = new ServiceContainer()
    this.app = new Hono()
    this.eventBus = new EventBus()
    this.scheduler = new TaskScheduler()
    this.config = null
    this.logger = null
    this.db = null
    this.wsManager = null
    this.server = null
  }
  
  async init() {
    try {
      this.config = new ConfigManager()
      this.logger = createLogger(this.config.get('base.logger'))
      this.logger.info('Application', '🚀 Starting ZitMapX Backend...')
      
      this.logger.info('Application', '✅ Configuration loaded')
      
      this.db = new Database('./storage/zitmapx.db')
      await this.initDatabase()
      this.logger.info('Application', '✅ Database initialized')
      
      this.wsManager = new WebSocketManager(this.logger)
      this.logger.info('Application', '✅ WebSocket manager initialized')
      
      this.setupMiddleware()
      
      this.registerCoreServices()
      this.logger.info('Application', '✅ Core services registered')
      
      await this.container.loadServices('./services/modules')
      this.logger.info('Application', '✅ Service modules loaded')
      
      await this.container.bootstrap(this)
      this.logger.info('Application', '✅ Services bootstrapped')
      
      this.setupDefaultRoutes()
      
      await this.start()
      
    } catch (err) {
      if (this.logger) {
        this.logger.error('Application', '❌ Failed to initialize application:', { error: err.message })
      } else {
        console.error('❌ Failed to initialize application:', err)
      }
      throw err
    }
  }
  
  async initDatabase() {
    this.db.exec('PRAGMA journal_mode = WAL')
    this.db.exec('PRAGMA synchronous = NORMAL')
    this.db.exec('PRAGMA cache_size = -64000')
    this.db.exec('PRAGMA temp_store = MEMORY')
    
    const schemaFile = Bun.file('./storage/schema.sql')
    const schema = await schemaFile.text()
    this.db.exec(schema)
  }
  
  setupMiddleware() {
    this.app.use('*', cors({
      origin: '*',
      allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
      allowHeaders: ['Content-Type', 'Authorization']
    }))
    
    this.app.use('*', logger())
    
    this.app.use('*', async (c, next) => {
      const start = Date.now()
      await next()
      const ms = Date.now() - start
      c.header('X-Response-Time', `${ms}ms`)
    })
  }
  
  registerCoreServices() {
    // 核心服务不需要注册到容器，它们是 Application 的内置属性
    // 服务模块可以通过 this.app 直接访问
    // this.app.config, this.app.logger, this.app.db, this.app.eventBus, this.app.scheduler
  }
  
  setupDefaultRoutes() {
    this.app.get('/health', c => c.json({
      status: 'ok',
      timestamp: Date.now(),
      uptime: process.uptime(),
      version: '2.0.0'
    }))
    
    this.app.get('/config', c => c.json(this.config.getAll()))
    
    this.app.get('/api/scheduler/tasks', c => {
      return c.json(this.scheduler.getTasks())
    })
    
    this.app.post('/api/scheduler/trigger/:task', async c => {
      const task = c.req.param('task')
      
      try {
        const result = await this.scheduler.triggerTask(task)
        return c.json({ success: true, result })
      } catch (err) {
        return c.json({ error: err.message }, 500)
      }
    })
    
    this.app.get('/', c => c.text('ZitMapX Backend v2.0'))
    
    this.app.notFound(c => c.json({ error: 'Not Found' }, 404))
    
    this.app.onError((err, c) => {
      this.logger.error('Application', 'Request error:', { error: err.message, stack: err.stack })
      return c.json({ error: err.message }, 500)
    })
  }
  
  async start() {
    const port = this.config.get('base.port', 8700)
    
    this.server = Bun.serve({
      port,
      fetch: this.app.fetch,
      websocket: {
        open: ws => this.wsManager.onOpen(ws),
        message: (ws, msg) => this.wsManager.onMessage(ws, msg),
        close: ws => this.wsManager.onClose(ws),
        error: (ws, err) => this.wsManager.onError(ws, err),
        ping: ws => ws.pong()
      }
    })
    
    this.logger.info('Application', `✅ Server started on port ${port}`)
    this.logger.info('Application', `📡 HTTP: http://localhost:${port}`)
    this.logger.info('Application', `🔌 WebSocket: ws://localhost:${port}`)
  }
  
  async stop() {
    if (this.server) {
      this.server.stop()
    }
    
    this.scheduler.stop()
    
    if (this.db) {
      this.db.close()
    }
    
    this.logger.info('Application', 'Server stopped')
  }
}